using System;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;

namespace HF.Repository
{
    public static class PredicateBuilder
    {
        public static Expression<Func<T, bool>> True<T>(T t)
        {
            return f => true;
        }

        public static Expression<Func<T, bool>> False<T>(T t)
        {
            return f => false;
        }

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
                                                      Expression<Func<T, bool>> expr2)
        {
            if (null != expr1 && null != expr2)
            {
                return Expression.Lambda<Func<T, bool>>
                    (Expression.Or(expr1.Body, expr2.Body), expr1.Parameters);

            }

            if (null != expr1)
            {
                return expr1;
            }
            if (null != expr2)
            {
                return expr2;
            }

            throw new RepositoryNullArgumentException();


            // InvocationExpression invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            //  return Expression.Lambda<Func<T, bool>>
            //      (Expression.Or(expr1.Body, invokedExpr), expr1.Parameters);
        }

        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
                                                       Expression<Func<T, bool>> expr2)
        {
            if (null != expr1 && null != expr2)
            {
                return Expression.Lambda<Func<T, bool>>
                (Expression.And(expr1.Body, expr2.Body), expr1.Parameters);

            }

            if (null != expr1)
            {
                return expr1;
            }
            if (null != expr2)
            {
                return expr2;
            }

            throw new RepositoryNullArgumentException();

            //   InvocationExpression invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            //   return Expression.Lambda<Func<T, bool>>
            //       (Expression.And(expr1.Body, invokedExpr), expr1.Parameters);

        }
    }
}